package com.edyd.customer.api.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.*;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Greg.chen on 2016/3/12.
 */
@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport{

    @Bean
    public RedisTemplate<String, String> redisTemplate(
            RedisConnectionFactory factory) {
        StringRedisTemplate template = new StringRedisTemplate(factory);

        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);

        // 默认过期时间
        cacheManager.setDefaultExpiration(3600);
        Map<String, Long> expires = new HashMap<>();
        expires.put("client", 7200l);
        cacheManager.setExpires(expires);

        return cacheManager;
    }

    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object o, Method method, Object... objects) {

                StringBuilder sb = new StringBuilder();

                if (method.isAnnotationPresent(Cacheable.class)) {
                    Cacheable annotation = method.getAnnotation(Cacheable.class);
                    sb.append(annotation.value()[0]);

                } else if (method.isAnnotationPresent(CachePut.class)) {
                    CachePut annotation = method.getAnnotation(CachePut.class);
                    sb.append(annotation.value()[0]);
                } else if (method.isAnnotationPresent(CacheEvict.class)) {
                    CacheEvict annotation = method.getAnnotation(CacheEvict.class);
                    sb.append(annotation.value()[0]);
                }

                sb.append(":");

                Annotation[][] parameterAnnotations = method.getParameterAnnotations();
                for (int i = 0; i < objects.length; i++) {

                    if (parameterAnnotations[i].length <= 0)
                        continue;

                    Annotation annotation = parameterAnnotations[i][0];
                    if (annotation.annotationType().getName().equals(CacheKey.class.getName())) {
                        sb.append(objects[i].toString());
                    }
                }
                return sb.toString();
            }
        };
    }
}


